package com.kymatrix.mpo.plus.bpm.server.service.impl;

import cn.hutool.core.util.StrUtil;
import com.kymatrix.mpo.plus.bpm.server.dao.definition.BpmProcessListenerMapper;
import com.kymatrix.mpo.plus.bpm.server.model.entity.definition.BpmProcessListenerEntity;
import com.kymatrix.mpo.plus.bpm.server.model.enums.definition.BpmProcessListenerType;
import com.kymatrix.mpo.plus.bpm.server.model.enums.definition.BpmProcessListenerValueType;
import com.kymatrix.mpo.plus.bpm.server.model.form.listener.PageQueryBpmProcessListenerReq;
import com.kymatrix.mpo.plus.bpm.server.model.form.listener.SaveBpmProcessListenerReq;
import com.kymatrix.mpo.plus.bpm.server.model.form.listener.UpdateBpmProcessListenerReq;
import com.kymatrix.mpo.plus.bpm.server.service.BpmProcessListenerService;
import com.kymatrix.mpo.plus.common.business.common.PageResp;
import com.kymatrix.mpo.plus.common.exception.BusinessException;
import javax.annotation.Resource;
import org.flowable.engine.delegate.JavaDelegate;
import org.flowable.engine.delegate.TaskListener;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import static com.kymatrix.mpo.plus.bpm.server.model.enums.ErrorCodeConstants.PROCESS_LISTENER_CLASS_IMPLEMENTS_ERROR;
import static com.kymatrix.mpo.plus.bpm.server.model.enums.ErrorCodeConstants.PROCESS_LISTENER_CLASS_NOT_FOUND;
import static com.kymatrix.mpo.plus.bpm.server.model.enums.ErrorCodeConstants.PROCESS_LISTENER_EXPRESSION_INVALID;
import static com.kymatrix.mpo.plus.bpm.server.model.enums.ErrorCodeConstants.PROCESS_LISTENER_NOT_EXISTS;

/**
 * BPM 流程监听器 Service 实现类
 */
@Service
@Validated
public class BpmProcessListenerServiceImpl implements BpmProcessListenerService {

    @Resource
    private BpmProcessListenerMapper processListenerMapper;

    @Override
    public String createProcessListener(SaveBpmProcessListenerReq req) {
        // 校验
        validateCreateProcessListenerValue(req.getType(), req.getValueType(), req.getValue());
        BpmProcessListenerEntity entity = new BpmProcessListenerEntity();
        entity.setName(req.getName());
        entity.setStatus(req.getStatus());
        entity.setType(req.getType());
        entity.setEvent(req.getEvent());
        entity.setValueType(req.getValueType());
        entity.setValue(req.getValue());
        processListenerMapper.insert(entity);
        return entity.getId();
    }

    private void validateCreateProcessListenerValue(String type, String valueType, String value) {
        // class 类型
        if (valueType.equals(BpmProcessListenerValueType.CLASS.getType())) {
            try {
                Class<?> clazz = Class.forName(value);
                if (type.equals(BpmProcessListenerType.EXECUTION.getType())
                        && !JavaDelegate.class.isAssignableFrom(clazz)) {
                    throw new BusinessException(PROCESS_LISTENER_CLASS_IMPLEMENTS_ERROR, value, JavaDelegate.class.getName());
                } else if (type.equals(BpmProcessListenerType.TASK.getType())
                        && !TaskListener.class.isAssignableFrom(clazz)) {
                    throw new BusinessException(PROCESS_LISTENER_CLASS_IMPLEMENTS_ERROR, value, TaskListener.class.getName());
                }
            } catch (ClassNotFoundException e) {
                throw new BusinessException(PROCESS_LISTENER_CLASS_NOT_FOUND, value);
            }
            return;
        }
        // 表达式
        if (!StrUtil.startWith(value, "${") || !StrUtil.endWith(value, "}")) {
            throw new BusinessException(PROCESS_LISTENER_EXPRESSION_INVALID, value);
        }
    }

    @Override
    public void updateProcessListener(UpdateBpmProcessListenerReq req) {
        // 校验存在
        validateProcessListenerExists(req.getId());
        validateCreateProcessListenerValue(req.getType(), req.getValueType(), req.getValue());
        BpmProcessListenerEntity entity = this.processListenerMapper.selectById(req.getId());
        entity.setName(req.getName());
        entity.setStatus(req.getStatus());
        entity.setType(req.getType());
        entity.setEvent(req.getEvent());
        entity.setValueType(req.getValueType());
        entity.setValue(req.getValue());
        processListenerMapper.updateById(entity);
    }

    @Override
    public void deleteProcessListener(String id) {
        processListenerMapper.deleteById(id);
    }

    private void validateProcessListenerExists(String id) {
        if (processListenerMapper.selectById(id) == null) {
            throw new BusinessException(PROCESS_LISTENER_NOT_EXISTS);
        }
    }

    @Override
    public BpmProcessListenerEntity getProcessListener(String id) {
        return processListenerMapper.selectById(id);
    }

    @Override
    public PageResp<BpmProcessListenerEntity> getProcessListenerPage(PageQueryBpmProcessListenerReq req) {
        return processListenerMapper.selectPage(req);
    }

}
